package org.tloss.web.editor.utils;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.tloss.web.editor.GeneratorHelper;
import org.tloss.web.editor.Utils;
import org.tloss.web.editor.database.editors.jdbc.Table;
import org.tloss.web.editor.model.Database;
import org.tloss.web.editor.model.Form;
import org.tloss.web.editor.model.Sql;
import org.tloss.web.spring.FormMapping;
import org.tloss.web.spring.View;
import org.tloss.web.spring.ViewMapping;

public class Generator {
	protected static void setParam(VelocityContext vecontext,
			Map<String, Object> codeData, String name, Object value) {
		vecontext.put(name, value);
		codeData.put(name, value);
	}

	public static IStatus generateForm(IProject project, IResource container,
			IProgressMonitor monitor, GeneratorHelper generatorHelper) {
		if (container != null && container.getType() == IResource.FOLDER) {
			try {
				Generator.generateForm(project,
						((IFolder) container).members(), monitor,
						generatorHelper);
			} catch (CoreException e) {
				Utils.logError("Can't create form package", e);
				return Status.CANCEL_STATUS;
			}
		}
		return Status.OK_STATUS;
	}

	public static IStatus generateForm(IProject project, IResource[] resources,
			IProgressMonitor monitor, GeneratorHelper generatorHelper) {
		if (project != null) {

			Properties config = Utils.getProperties(project);
			IResource src = project.findMember(config.getProperty(
					Constants.SRC_FOLDER_PRO, Constants.SRC_FOLDER));
			IResource srcResource = project.findMember(config.getProperty(
					Constants.SRC_RESOURCE_FOLDER_PRO,
					Constants.SRC_RESOURCE_FOLDER));
			if (src != null && src.getType() == IResource.FOLDER) {
				IFolder srcForm = ((IFolder) src)
						.getFolder(Constants.FORMS_FOLDER);
				if (!srcForm.exists()) {
					try {
						srcForm.create(true, true, monitor);
					} catch (CoreException e) {
						Utils.logError("Can't create form package", e);
						srcForm = null;
						return Status.CANCEL_STATUS;
					}
				}
				if (srcForm != null) {

					VelocityEngine ve;

					ve = new VelocityEngine();
					ve.setProperty(RuntimeConstants.RESOURCE_LOADER,
							"classpath");
					ve.setProperty("classpath.resource.loader.class",
							ClasspathResourceLoader.class.getName());

					ve.init();

					VelocityContext vecontext = new VelocityContext();
					ViewMapping viewMapping = new ViewMapping();
					viewMapping.setFormMappings(new ArrayList<FormMapping>());
					try {
						String name;
						String ext;
						String newName;
						IFile javaFile;
						IFile javaFile2;
						if (resources != null) {
							JAXBContext context;
							context = JAXBContext.newInstance(Form.class);
							Unmarshaller marshaller = context
									.createUnmarshaller();
							InputStream stream = null;
							Template template = null;
							Template template2 = null;
							for (int i = 0; i < resources.length; i++) {
								if (resources[i] != null
										&& resources[i].getType() == IResource.FILE) {
									name = ((IFile) resources[i]).getName();
									ext = ((IFile) resources[i])
											.getFileExtension();
									if (Constants.FORMS_EXT.equals(ext)) {
										newName = name.substring(0,
												name.length() - ext.length())
												+ "java";
										javaFile = srcForm.getFile(newName);
										javaFile2 = srcForm.getFile(name
												.substring(0, name.length()
														- ext.length() - 1)
												+ "Form.java");
										ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
										ByteArrayOutputStream byteArrayOutputStream2 = new ByteArrayOutputStream();
										stream = ((IFile) resources[i])
												.getContents();

										Form form = (Form) marshaller
												.unmarshal(stream);

										template = ve.getTemplate(
												Constants.FORM_TEMPLATE,
												"UTF-8");
										template2 = ve.getTemplate(
												Constants.FORM__VIEWTEMPLATE,
												"UTF-8");
										String formName = name.substring(0,
												name.length() - ext.length()
														- 1);
										Map<String, Object> codeData = new HashMap<String, Object>();
										FormMapping formMapping = new FormMapping();
										formMapping
												.setViews(new ArrayList<View>());
										formMapping.setName(formName);
										viewMapping.getFormMappings().add(
												formMapping);
										setParam(vecontext, codeData,
												"formMapping", formMapping);
										setParam(vecontext, codeData, "form",
												form);
										setParam(vecontext, codeData,
												"codeType",
												Constants.CodeType.JAVA);
										vecontext.put("codeData",
												new Object[] { codeData });
										setParam(vecontext, codeData,
												"generatorHelper",
												generatorHelper);
										setParam(vecontext, codeData,
												"entityPackage",
												Constants.ENTITY_FOLDER);
										setParam(vecontext, codeData,
												"sqlPackage",
												Constants.SQL_FOLDER);
										setParam(vecontext, codeData,
												"formName", formName);
										setParam(vecontext, codeData,
												"package",
												Constants.FORMS_FOLDER);
										setParam(
												vecontext,
												codeData,
												"className",
												name.substring(0, name.length()
														- ext.length() - 1));
										setParam(vecontext, codeData, "config",
												config);
										OutputStreamWriter writer = new OutputStreamWriter(
												byteArrayOutputStream);
										OutputStreamWriter writer2 = new OutputStreamWriter(
												byteArrayOutputStream2);
										template.merge(vecontext, writer);

										template2.merge(vecontext, writer2);
										writer.flush();
										writer.close();
										writer2.flush();
										writer2.close();
										stream.close();
										if (javaFile.exists()) {
											javaFile.setContents(
													new ByteArrayInputStream(
															byteArrayOutputStream
																	.toByteArray()),
													true, false, monitor);
										} else {
											javaFile.create(
													new ByteArrayInputStream(
															byteArrayOutputStream
																	.toByteArray()),
													true, monitor);
										}
										if (javaFile2.exists()) {
											javaFile2
													.setContents(
															new ByteArrayInputStream(
																	byteArrayOutputStream2
																			.toByteArray()),
															true, false,
															monitor);
										} else {
											javaFile2
													.create(new ByteArrayInputStream(
															byteArrayOutputStream2
																	.toByteArray()),
															true, monitor);
										}
									}
								}
							}
						}
					} catch (CoreException e) {
						Utils.logError("Can't generate form", e);
						return Status.CANCEL_STATUS;
					} catch (JAXBException e) {
						Utils.logError("Can't generate form", e);
						return Status.CANCEL_STATUS;
					} catch (IOException e) {
						Utils.logError("Can't generate form", e);
						return Status.CANCEL_STATUS;
					}
					if (srcResource != null
							&& srcResource.getType() == IResource.FOLDER) {
						try {
							IFile javaFile;
							javaFile = ((IFolder) srcResource)
									.getFile(Constants.VIEWMAPPING_FILE);

							ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
							JAXBContext context = JAXBContext
									.newInstance(ViewMapping.class);
							Marshaller marshaller = context.createMarshaller();
							marshaller.marshal(viewMapping,
									byteArrayOutputStream);
							if (javaFile.exists()) {
								javaFile.setContents(new ByteArrayInputStream(
										byteArrayOutputStream.toByteArray()),
										true, false, monitor);
							} else {
								javaFile.create(new ByteArrayInputStream(
										byteArrayOutputStream.toByteArray()),
										true, monitor);
							}
						} catch (CoreException e) {
							Utils.logError("Can't generate viewMapping", e);
							return Status.CANCEL_STATUS;
						} catch (JAXBException e) {
							Utils.logError("Can't generate viewMapping", e);
							return Status.CANCEL_STATUS;
						}
					}
					return Status.OK_STATUS;
				}
			}
		}
		return Status.OK_STATUS;
	}

	public static IStatus generateDataSource(IProject project,
			IResource resource, IProgressMonitor monitor) {
		if (project != null) {

			Properties config = Utils.getProperties(project);
			IResource srcResource = project.findMember(config.getProperty(
					Constants.SRC_RESOURCE_FOLDER_PRO,
					Constants.SRC_RESOURCE_FOLDER));
			if (srcResource != null
					&& srcResource.getType() == IResource.FOLDER) {
				VelocityEngine ve;
				ve = new VelocityEngine();
				ve.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath");
				ve.setProperty("classpath.resource.loader.class",
						ClasspathResourceLoader.class.getName());
				ve.init();
				VelocityContext vecontext = new VelocityContext();
				ViewMapping viewMapping = new ViewMapping();
				viewMapping.setFormMappings(new ArrayList<FormMapping>());
				try {
					String ext;
					String newName;
					IFile springJDBCFile;
					if (resource != null) {
						JAXBContext context;
						context = JAXBContext.newInstance(Database.class);
						Unmarshaller marshaller = context.createUnmarshaller();
						InputStream stream = null;
						Template template = null;
						if (resource != null
								&& resource.getType() == IResource.FILE) {
							ext = ((IFile) resource).getFileExtension();
							if (Constants.DATABASE_EXT.equals(ext)) {
								newName = "spring-jdbc.xml";
								springJDBCFile = ((IFolder) srcResource)
										.getFile(newName);
								ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
								stream = ((IFile) resource).getContents();
								Database database = (Database) marshaller
										.unmarshal(stream);
								template = ve
										.getTemplate(
												Constants.SPRING_JDBC_TEMPLATE,
												"UTF-8");
								vecontext.put("database", database);
								OutputStreamWriter writer = new OutputStreamWriter(
										byteArrayOutputStream);
								template.merge(vecontext, writer);
								writer.flush();
								writer.close();
								stream.close();
								if (springJDBCFile.exists()) {
									springJDBCFile.setContents(
											new ByteArrayInputStream(
													byteArrayOutputStream
															.toByteArray()),
											true, false, monitor);
								} else {
									springJDBCFile.create(
											new ByteArrayInputStream(
													byteArrayOutputStream
															.toByteArray()),
											true, monitor);
								}
							}
						}
					}
				} catch (CoreException e) {
					Utils.logError("Can't generate form", e);
					return Status.CANCEL_STATUS;
				} catch (JAXBException e) {
					Utils.logError("Can't generate form", e);
					return Status.CANCEL_STATUS;
				} catch (IOException e) {
					Utils.logError("Can't generate form", e);
					return Status.CANCEL_STATUS;
				}
				return Status.OK_STATUS;
			}
		}
		return Status.OK_STATUS;
	}

	public static IStatus generateSQL(IProject project, IResource[] resources,
			IProgressMonitor monitor, GeneratorHelper generatorHelper) {
		if (project != null) {
			IResource src = project.findMember(Utils.getProperty(project,
					Constants.SRC_FOLDER_PRO, Constants.SRC_FOLDER));
			if (src != null && src.getType() == IResource.FOLDER) {
				IFolder srcSql = ((IFolder) src)
						.getFolder(Constants.SQL_FOLDER);
				if (!srcSql.exists()) {
					try {
						srcSql.create(true, true, monitor);
					} catch (CoreException e) {
						Utils.logError("Can't create sql package", e);
						srcSql = null;
						return Status.CANCEL_STATUS;
					}
				}
				if (srcSql != null) {
					VelocityEngine ve;

					ve = new VelocityEngine();
					ve.setProperty(RuntimeConstants.RESOURCE_LOADER,
							"classpath");
					ve.setProperty("classpath.resource.loader.class",
							ClasspathResourceLoader.class.getName());

					ve.init();

					VelocityContext vecontext = new VelocityContext();
					try {
						String name;
						String ext;
						String newName;
						IFile javaFile;
						if (resources != null) {
							JAXBContext context;
							context = JAXBContext.newInstance(Sql.class);
							Unmarshaller marshaller = context
									.createUnmarshaller();
							InputStream stream = null;
							Template template = null;
							for (int i = 0; i < resources.length; i++) {
								if (resources[i] != null
										&& resources[i].getType() == IResource.FILE) {
									name = ((IFile) resources[i]).getName();
									ext = ((IFile) resources[i])
											.getFileExtension();
									if (Constants.SQL_EXT.equals(ext)) {
										newName = name.substring(0,
												name.length() - ext.length())
												+ "java";
										javaFile = srcSql.getFile(newName);
										ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
										stream = ((IFile) resources[i])
												.getContents();
										Sql sql = (Sql) marshaller
												.unmarshal(stream);
										if (Constants.SQL_SELECT_MODE
												.equals(sql.getMode())) {
											template = ve
													.getTemplate(
															Constants.SELECT_SQL_VELOCITY_TEMPLATE,
															"UTF-8");
										} else if (Constants.SQL_DELETE_MODE
												.equals(sql.getMode())) {
											template = ve
													.getTemplate(
															Constants.DELETE_SQL_VELOCITY_TEMPLATE,
															"UTF-8");
										} else if (Constants.SQL_INSERT_MODE
												.equals(sql.getMode())) {
											template = ve
													.getTemplate(
															Constants.INSERT_SQL_VELOCITY_TEMPLATE,
															"UTF-8");
										}
										if (Constants.SQL_UPDATE_MODE
												.equals(sql.getMode())) {
											template = ve
													.getTemplate(
															Constants.UPDATE_SQL_VELOCITY_TEMPLATE,
															"UTF-8");
										}
										vecontext.put("sql", sql);
										vecontext.put("generatorHelper",
												generatorHelper);
										vecontext.put("entityPackage",
												Constants.ENTITY_FOLDER);
										vecontext.put("package",
												Constants.SQL_FOLDER);
										vecontext.put(
												"className",
												name.substring(0, name.length()
														- ext.length() - 1));
										OutputStreamWriter writer = new OutputStreamWriter(
												byteArrayOutputStream);
										template.merge(vecontext, writer);

										writer.flush();
										writer.close();

										stream.close();
										if (javaFile.exists()) {
											javaFile.setContents(
													new ByteArrayInputStream(
															byteArrayOutputStream
																	.toByteArray()),
													true, false, monitor);
										} else {
											javaFile.create(
													new ByteArrayInputStream(
															byteArrayOutputStream
																	.toByteArray()),
													true, monitor);
										}
									}
								}
							}
						}
					} catch (CoreException e) {
						Utils.logError("Can't generate sql", e);
						return Status.CANCEL_STATUS;
					} catch (JAXBException e) {
						Utils.logError("Can't generate sql", e);
						return Status.CANCEL_STATUS;
					} catch (IOException e) {
						Utils.logError("Can't generate sql", e);
						return Status.CANCEL_STATUS;
					}
					return Status.OK_STATUS;
				}
			}
		}
		return Status.OK_STATUS;
	}

	public static IStatus generateSQL(IProject project, IResource container,
			IProgressMonitor monitor, GeneratorHelper generatorHelper) {
		if (container != null && container.getType() == IResource.FOLDER) {
			try {
				Generator.generateSQL(project, ((IFolder) container).members(),
						monitor, generatorHelper);
			} catch (CoreException e) {
				Utils.logError("Can't create sql package", e);
				return Status.CANCEL_STATUS;
			}
		}
		return Status.OK_STATUS;
	}

	public static IStatus generateEntity(IProject project,
			IResource[] resources, IProgressMonitor monitor) {
		if (project != null) {
			IResource src = project.findMember(Utils.getProperty(project,
					Constants.SRC_FOLDER_PRO, Constants.SRC_FOLDER));
			if (src != null && src.getType() == IResource.FOLDER) {
				IFolder srcEntities = ((IFolder) src)
						.getFolder(Constants.ENTITY_FOLDER);
				if (!srcEntities.exists()) {
					try {
						srcEntities.create(true, true, monitor);
					} catch (CoreException e) {
						Utils.logError("Can't create entities package", e);
						srcEntities = null;
						return Status.CANCEL_STATUS;
					}
				}
				if (srcEntities != null) {
					VelocityEngine ve;

					ve = new VelocityEngine();
					ve.setProperty(RuntimeConstants.RESOURCE_LOADER,
							"classpath");
					ve.setProperty("classpath.resource.loader.class",
							ClasspathResourceLoader.class.getName());

					ve.init();

					VelocityContext vecontext = new VelocityContext();
					try {
						String name;
						String ext;
						String newName;
						IFile javaFile;
						if (resources != null) {
							JAXBContext context;
							context = JAXBContext.newInstance(Table.class);
							Unmarshaller marshaller = context
									.createUnmarshaller();
							InputStream stream = null;
							Template template = ve.getTemplate(
									"/templates/entities.vm", "UTF-8");
							for (int i = 0; i < resources.length; i++) {
								if (resources[i] != null
										&& resources[i].getType() == IResource.FILE) {
									name = ((IFile) resources[i]).getName();
									ext = ((IFile) resources[i])
											.getFileExtension();
									if (Constants.ENTITY_EXT.equals(ext)) {
										newName = name.substring(0,
												name.length() - ext.length())
												+ "java";
										javaFile = srcEntities.getFile(newName);
										ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
										stream = ((IFile) resources[i])
												.getContents();
										Table table = (Table) marshaller
												.unmarshal(stream);
										vecontext.put("table", table);
										vecontext.put("package",
												Constants.ENTITY_FOLDER);
										vecontext.put(
												"className",
												name.substring(0, name.length()
														- ext.length() - 1));
										OutputStreamWriter writer = new OutputStreamWriter(
												byteArrayOutputStream);
										template.merge(vecontext, writer);

										writer.flush();
										writer.close();

										stream.close();
										if (javaFile.exists()) {
											javaFile.setContents(
													new ByteArrayInputStream(
															byteArrayOutputStream
																	.toByteArray()),
													true, false, monitor);
										} else {
											javaFile.create(
													new ByteArrayInputStream(
															byteArrayOutputStream
																	.toByteArray()),
													true, monitor);
										}
									}
								}
							}
						}
					} catch (CoreException e) {
						Utils.logError("Can't generate entity", e);
						return Status.CANCEL_STATUS;
					} catch (JAXBException e) {
						Utils.logError("Can't generate entity", e);
						return Status.CANCEL_STATUS;
					} catch (IOException e) {
						Utils.logError("Can't generate entity", e);
						return Status.CANCEL_STATUS;
					}
				}

			}
		}
		return Status.OK_STATUS;
	}

	public static IStatus generateEntity(IProject project, IResource container,
			IProgressMonitor monitor) {
		if (container != null && container.getType() == IResource.FOLDER) {
			try {
				return generateEntity(project, ((IFolder) container).members(),
						monitor);
			} catch (CoreException e) {
				Utils.logError("Can't generate entity", e);
				return Status.CANCEL_STATUS;
			}
		}
		return Status.OK_STATUS;
	}

	public static IStatus generateDAO(IProject project, IResource[] resources,
			IProgressMonitor monitor) {
		if (project != null) {
			IResource src = project.findMember(Utils.getProperty(project,
					Constants.SRC_RESOURCE_FOLDER_PRO,
					Constants.SRC_RESOURCE_FOLDER));
			if (src != null && src.getType() == IResource.FOLDER) {
				IFolder srcEntities = ((IFolder) src);
				if (srcEntities != null) {
					VelocityEngine ve;

					ve = new VelocityEngine();
					ve.setProperty(RuntimeConstants.RESOURCE_LOADER,
							"classpath");
					ve.setProperty("classpath.resource.loader.class",
							ClasspathResourceLoader.class.getName());

					ve.init();

					VelocityContext vecontext = new VelocityContext();
					try {
						String ext;
						String newName;
						IFile javaFile;
						if (resources != null) {
							Template template = ve.getTemplate(
									"/templates/spring_dao.vm", "UTF-8");
							List<String> sqls = new ArrayList<String>();
							String name;
							for (int i = 0; i < resources.length; i++) {
								if (resources[i] != null
										&& resources[i].getType() == IResource.FILE) {
									name = ((IFile) resources[i]).getName();
									ext = ((IFile) resources[i])
											.getFileExtension();
									if (Constants.SQL_EXT.equals(ext)) {
										sqls.add(name.substring(0, name.length()
												- ext.length() - 1));
									}
								}
							}

							newName = "spring-dao.xml";
							javaFile = srcEntities.getFile(newName);
							ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
							vecontext.put("sqls", sqls);
							vecontext.put("package", Constants.SQL_FOLDER);
							OutputStreamWriter writer = new OutputStreamWriter(
									byteArrayOutputStream);
							template.merge(vecontext, writer);
							writer.flush();
							writer.close();
							if (javaFile.exists()) {
								javaFile.setContents(new ByteArrayInputStream(
										byteArrayOutputStream.toByteArray()),
										true, false, monitor);
							} else {
								javaFile.create(new ByteArrayInputStream(
										byteArrayOutputStream.toByteArray()),
										true, monitor);
							}

						}
					} catch (CoreException e) {
						Utils.logError("Can't generate entity", e);
						return Status.CANCEL_STATUS;
					} catch (IOException e) {
						Utils.logError("Can't generate entity", e);
						return Status.CANCEL_STATUS;
					}
				}

			}
		}
		return Status.OK_STATUS;
	}

}
